package com.atguigu.day02;

import java.util.concurrent.TimeUnit;

/**
 * @ClassName Lock8Demo
 * @Description 此类描述:
 * @Author dangchen
 * @DateTime 2022-09-07 18:51
 * @Version 1.0
 */

/*
以高内聚低耦合为前提
线程 操作 资源类
 */
class Phone{
    public static synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-------email-----");
    }

    public synchronized void sendSMS(){
        System.out.println("--------------SMS--------");
    }
    public void hello(){
        System.out.println("---hello---");
    }
}
/*
多线程锁的情况,它到底锁的是什么?

1.标准访问,请问先打印邮件还是短信? 邮件
2.邮件方法暂停3秒钟,请问先打印邮件还是短信? 邮件

1-2 一个对象里面如果有多个synchronized方法,在某一时刻内,只要一个线程去调用其中的一个synchronized方法了,其他的线程都只能等待,换句话说,某一时刻内,只能有唯一一个线程去访问synchronized方法.
锁的是当前对象this,被锁定后,其他的线程都不能进入到当前对象的其他synchronized方法

3.新增hello普通方法,请问先打印邮件还是hello? hello
4.两部手机,请问先打印邮件还是短信? 短信

3-4 加个普通方法后发现和同步锁无关,被锁定后,其他的线程都不能进入到当前对象的其他的synchronized方法,但是非synchronized的访问不受影响.
换成两个对象后,不是同一把锁了,情况发生变化,因为在访问不同的锁的synchronized非法,相互之间没有关系

5.两个静态同步方法,一部手机,请问先打印邮件还是短信? 邮件
6.两个静态同步方法,两部手机,请问先打印邮件还是短信? 邮件

5-6 都换成静态方法后,情况又有变化

Phone        phone = new Phone()
模板类对象    引用    实例对象

若是普通同步方法,new this,具体的一部部手机,所有的普通同步方法用的都是同一把锁---实例对象本身;若是静态同步方法,static Class ,唯一的一个模板

7.一个普通同步方法,一个静态同步方法,一部手机,请问先打印邮件还是短信? 短信
8.一个普通同步方法,一个静态同步方法,两部手机,请问先打印邮件还是短信? 短信

7-8 当一个线程试图访问同步代码时它首先必须得到锁,退出或抛出异常时必须释放锁.
所有的普通同步方法用的都是同一把锁--实例对象本身,就是new出来的具体实例对象本身,也就是说如果一个实例对象的普通方法获取锁后,该实例对象的其他普通同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的普通同步方法因为跟该实例对象的普通同步方法用的是不同的锁,所以不用等待该实例对象已获取锁的普通同步方法释放锁就可以获取他们自己的锁.
所有的静态同步方法用的也是同一把锁--类对象本身,就是我们说过的唯一模版Class,具体实例对象this和唯一模板Class,这两把锁是两个不同的对象,所以静态同步方法与普通同步方法之间是不会有竞态条件的,但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁
 */
public class Lock8Demo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> { phone.sendEmail();},"t1").start();

        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            phone.sendSMS();
            //phone2.sendSMS();
            //phone.hello();
            },"t2").start();
    }
}
